mcp-probe-kit 1.10.1 → 1.13.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/README.md +164 -21
- package/build/index.js +30 -451
- package/build/resources/index.d.ts +4 -0
- package/build/resources/index.js +4 -0
- package/build/resources/tool-params-guide.d.ts +571 -0
- package/build/resources/tool-params-guide.js +488 -0
- package/build/schemas/basic-tools.d.ts +54 -0
- package/build/schemas/basic-tools.js +58 -0
- package/build/schemas/code-analysis-tools.d.ts +156 -0
- package/build/schemas/code-analysis-tools.js +165 -0
- package/build/schemas/code-gen-tools.d.ts +150 -0
- package/build/schemas/code-gen-tools.js +158 -0
- package/build/schemas/doc-util-tools.d.ts +85 -0
- package/build/schemas/doc-util-tools.js +93 -0
- package/build/schemas/git-tools.d.ts +76 -0
- package/build/schemas/git-tools.js +81 -0
- package/build/schemas/index.d.ts +893 -0
- package/build/schemas/index.js +22 -0
- package/build/schemas/interview-tools.d.ts +72 -0
- package/build/schemas/interview-tools.js +64 -0
- package/build/schemas/orchestration-tools.d.ts +244 -0
- package/build/schemas/orchestration-tools.js +255 -0
- package/build/schemas/project-tools.d.ts +84 -0
- package/build/schemas/project-tools.js +89 -0
- package/build/tools/add_feature.js +68 -5
- package/build/tools/ask_user.d.ts +17 -0
- package/build/tools/ask_user.js +124 -0
- package/build/tools/css_order.js +55 -55
- package/build/tools/index.d.ts +3 -0
- package/build/tools/index.js +4 -0
- package/build/tools/interview.d.ts +18 -0
- package/build/tools/interview.js +418 -0
- package/build/tools/start_feature.js +64 -7
- package/build/tools/start_ralph.d.ts +16 -0
- package/build/tools/start_ralph.js +779 -0
- package/build/utils/parseArgs.js +12 -1
- package/docs/BEST_PRACTICES.md +200 -6
- package/docs/HOW_TO_TRIGGER.html +14 -2
- package/docs/HOW_TO_TRIGGER.md +125 -64
- package/docs/MCP-Probe-Kit-/344/275/277/347/224/250/346/211/213/345/206/214.html +83 -48
- package/docs/MCP-Probe-Kit-/344/275/277/347/224/250/346/211/213/345/206/214.md +291 -34
- package/package.json +2 -2
|
@@ -0,0 +1,779 @@
|
|
|
1
|
+
import { parseArgs, getString, getNumber } from "../utils/parseArgs.js";
|
|
2
|
+
// 默认值(保守安全)
|
|
3
|
+
const DEFAULTS = {
|
|
4
|
+
mode: "safe",
|
|
5
|
+
completion_promise: "tests passing + requirements met",
|
|
6
|
+
test_command: "npm test",
|
|
7
|
+
cli_command: "claude-code",
|
|
8
|
+
max_iterations: 8,
|
|
9
|
+
max_minutes: 25,
|
|
10
|
+
confirm_every: 1,
|
|
11
|
+
confirm_timeout: 20,
|
|
12
|
+
max_same_output: 2,
|
|
13
|
+
max_diff_lines: 300,
|
|
14
|
+
cooldown_seconds: 8,
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* 生成 PROMPT.md 模板
|
|
18
|
+
*/
|
|
19
|
+
function generatePromptTemplate(goal, completionPromise, testCommand) {
|
|
20
|
+
return `# Ralph Wiggum Loop - Development Prompt
|
|
21
|
+
|
|
22
|
+
## 🎯 Goal
|
|
23
|
+
|
|
24
|
+
${goal}
|
|
25
|
+
|
|
26
|
+
## ✅ Completion Promise
|
|
27
|
+
|
|
28
|
+
**Exit Condition**: ${completionPromise}
|
|
29
|
+
|
|
30
|
+
You MUST satisfy BOTH conditions to exit:
|
|
31
|
+
1. \`COMPLETION_PROMISE_MET: true\`
|
|
32
|
+
2. \`EXIT_SIGNAL: true\`
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## 📋 Iteration Rules
|
|
36
|
+
|
|
37
|
+
### 1. Small Steps
|
|
38
|
+
- Make ONE focused change per iteration
|
|
39
|
+
- Avoid large refactors in a single iteration
|
|
40
|
+
- Keep changes under ${DEFAULTS.max_diff_lines} lines when possible
|
|
41
|
+
|
|
42
|
+
### 2. Test First
|
|
43
|
+
- **CRITICAL**: First iteration MUST identify the correct test command for this project
|
|
44
|
+
- Check for: package.json scripts, pytest, cargo test, go test, mvn test, etc.
|
|
45
|
+
- Update this PROMPT.md with the correct command
|
|
46
|
+
- Run tests EVERY iteration: \`${testCommand}\`
|
|
47
|
+
- Do NOT proceed if tests fail (unless fixing test failures is the goal)
|
|
48
|
+
|
|
49
|
+
### 3. Update Progress
|
|
50
|
+
- Update \`@fix_plan.md\` after each iteration
|
|
51
|
+
- Mark completed tasks with ✅
|
|
52
|
+
- Add new discovered tasks
|
|
53
|
+
- Adjust priorities
|
|
54
|
+
- Update \`PROGRESS.md\` with:
|
|
55
|
+
- What was done
|
|
56
|
+
- Test results
|
|
57
|
+
- Next step
|
|
58
|
+
- Current status
|
|
59
|
+
|
|
60
|
+
### 4. State Block (REQUIRED)
|
|
61
|
+
At the end of EVERY response, output:
|
|
62
|
+
|
|
63
|
+
\`\`\`
|
|
64
|
+
COMPLETION_PROMISE_MET: [true|false]
|
|
65
|
+
EXIT_SIGNAL: [true|false]
|
|
66
|
+
SUMMARY: [one-line summary of this iteration]
|
|
67
|
+
NEXT_STEP: [what to do next, or "EXIT" if done]
|
|
68
|
+
\`\`\`
|
|
69
|
+
|
|
70
|
+
**Exit Logic**:
|
|
71
|
+
- Set \`COMPLETION_PROMISE_MET: true\` only when completion promise is satisfied
|
|
72
|
+
- Set \`EXIT_SIGNAL: true\` only when you're confident to exit
|
|
73
|
+
- Loop continues if EITHER is false
|
|
74
|
+
|
|
75
|
+
### 5. Safety Checks
|
|
76
|
+
- If stuck or repeating same action → set \`EXIT_SIGNAL: true\` and ask for help
|
|
77
|
+
- If single change exceeds ${DEFAULTS.max_diff_lines} lines → stop and break into smaller tasks
|
|
78
|
+
- If tests keep failing after 3 attempts → stop and ask for help
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 📂 Files
|
|
83
|
+
|
|
84
|
+
- \`@fix_plan.md\`: Task breakdown and priorities
|
|
85
|
+
- \`PROGRESS.md\`: Iteration log
|
|
86
|
+
- \`STOP\`: Create this file to emergency stop
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
*Generated by MCP Probe Kit - start_ralph*
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 生成 @fix_plan.md 模板
|
|
95
|
+
*/
|
|
96
|
+
function generateFixPlanTemplate(goal) {
|
|
97
|
+
return `# Task Plan: ${goal}
|
|
98
|
+
|
|
99
|
+
## 🎯 Goal
|
|
100
|
+
${goal}
|
|
101
|
+
|
|
102
|
+
## 📋 Tasks
|
|
103
|
+
|
|
104
|
+
### ✅ Completed
|
|
105
|
+
- [ ] Identify correct test command
|
|
106
|
+
- [ ] Verify project structure
|
|
107
|
+
|
|
108
|
+
### 🚧 In Progress
|
|
109
|
+
- [ ] [Task will be added by agent]
|
|
110
|
+
|
|
111
|
+
### 📝 Todo
|
|
112
|
+
- [ ] [Tasks will be added by agent]
|
|
113
|
+
|
|
114
|
+
### 🔍 Discovered Issues
|
|
115
|
+
- [Issues will be added during iterations]
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
**Instructions for Agent**:
|
|
120
|
+
1. First iteration: identify test command and update PROMPT.md
|
|
121
|
+
2. Break down goal into small, testable tasks
|
|
122
|
+
3. Mark tasks as completed with ✅
|
|
123
|
+
4. Add new tasks as discovered
|
|
124
|
+
5. Keep this file updated every iteration
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 生成 PROGRESS.md 模板
|
|
129
|
+
*/
|
|
130
|
+
function generateProgressTemplate() {
|
|
131
|
+
return `# Ralph Loop Progress Log
|
|
132
|
+
|
|
133
|
+
## Iteration Summary
|
|
134
|
+
|
|
135
|
+
| Iter | Time | Changed Lines | Tests | Status | Summary |
|
|
136
|
+
|------|------|---------------|-------|--------|---------|
|
|
137
|
+
| 0 | - | - | - | START | Loop initialized |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Detailed Log
|
|
142
|
+
|
|
143
|
+
### Iteration 0 - Initialization
|
|
144
|
+
- **Time**: [timestamp]
|
|
145
|
+
- **Action**: Loop started
|
|
146
|
+
- **Next**: Identify test command and begin first task
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
**Instructions for Agent**:
|
|
151
|
+
- Add entry for each iteration
|
|
152
|
+
- Include: iteration number, timestamp, what was done, test results, next step
|
|
153
|
+
- Keep summary table updated
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 生成安全模式脚本 (Bash)
|
|
158
|
+
*/
|
|
159
|
+
function generateSafeScript(params) {
|
|
160
|
+
return `#!/bin/bash
|
|
161
|
+
# Ralph Loop - Safe Mode
|
|
162
|
+
# Generated by MCP Probe Kit
|
|
163
|
+
|
|
164
|
+
set -euo pipefail
|
|
165
|
+
|
|
166
|
+
# ============================================
|
|
167
|
+
# SAFETY PARAMETERS (Override with env vars)
|
|
168
|
+
# ============================================
|
|
169
|
+
MAX_ITERS=\${MAX_ITERS:-${params.max_iterations}}
|
|
170
|
+
MAX_MINUTES=\${MAX_MINUTES:-${params.max_minutes}}
|
|
171
|
+
CONFIRM_EVERY=\${CONFIRM_EVERY:-${params.confirm_every}}
|
|
172
|
+
CONFIRM_TIMEOUT=\${CONFIRM_TIMEOUT:-${params.confirm_timeout}}
|
|
173
|
+
MAX_SAME_OUTPUT=\${MAX_SAME_OUTPUT:-${params.max_same_output}}
|
|
174
|
+
MAX_DIFF_LINES=\${MAX_DIFF_LINES:-${params.max_diff_lines}}
|
|
175
|
+
COOLDOWN_SECONDS=\${COOLDOWN_SECONDS:-${params.cooldown_seconds}}
|
|
176
|
+
REQUIRE_TTY=\${REQUIRE_TTY:-1}
|
|
177
|
+
CLI_COMMAND=\${CLI_COMMAND:-${params.cli_command}}
|
|
178
|
+
|
|
179
|
+
# ============================================
|
|
180
|
+
# SAFETY CHECKS
|
|
181
|
+
# ============================================
|
|
182
|
+
if [ "$REQUIRE_TTY" = "1" ] && [ ! -t 0 ]; then
|
|
183
|
+
echo "❌ ERROR: Not running in interactive terminal (TTY required for safety)"
|
|
184
|
+
echo " To override: REQUIRE_TTY=0 $0"
|
|
185
|
+
exit 1
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
if [ ! -f "PROMPT.md" ]; then
|
|
189
|
+
echo "❌ ERROR: PROMPT.md not found. Run from .ralph/ directory"
|
|
190
|
+
exit 1
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
# ============================================
|
|
194
|
+
# STARTUP WARNING
|
|
195
|
+
# ============================================
|
|
196
|
+
echo "🚀 Ralph Loop - Safe Mode"
|
|
197
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
198
|
+
echo "⚠️ Safety Limits:"
|
|
199
|
+
echo " • Max iterations: $MAX_ITERS"
|
|
200
|
+
echo " • Max time: $MAX_MINUTES minutes"
|
|
201
|
+
echo " • Confirm every: $CONFIRM_EVERY iteration(s)"
|
|
202
|
+
echo " • Confirm timeout: $CONFIRM_TIMEOUT seconds"
|
|
203
|
+
echo " • Max same output: $MAX_SAME_OUTPUT times"
|
|
204
|
+
echo " • Max diff lines: $MAX_DIFF_LINES lines"
|
|
205
|
+
echo ""
|
|
206
|
+
echo "💡 Emergency stop: touch STOP"
|
|
207
|
+
echo "💡 Pause: Ctrl+C"
|
|
208
|
+
echo ""
|
|
209
|
+
echo "Press Ctrl+C to cancel, or wait 5s to start..."
|
|
210
|
+
sleep 5
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# ============================================
|
|
214
|
+
# INITIALIZATION
|
|
215
|
+
# ============================================
|
|
216
|
+
ITER=0
|
|
217
|
+
START_TIME=$(date +%s)
|
|
218
|
+
LAST_OUTPUT_HASH=""
|
|
219
|
+
SAME_OUTPUT_COUNT=0
|
|
220
|
+
LOG_FILE="ralph.log"
|
|
221
|
+
|
|
222
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] Loop started" >> "$LOG_FILE"
|
|
223
|
+
|
|
224
|
+
# ============================================
|
|
225
|
+
# MAIN LOOP
|
|
226
|
+
# ============================================
|
|
227
|
+
while [ $ITER -lt $MAX_ITERS ]; do
|
|
228
|
+
ITER=$((ITER + 1))
|
|
229
|
+
echo ""
|
|
230
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
231
|
+
echo "🔄 Iteration $ITER / $MAX_ITERS"
|
|
232
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
233
|
+
|
|
234
|
+
# Check: STOP file
|
|
235
|
+
if [ -f "STOP" ]; then
|
|
236
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SAFE] STOP file detected" >> "$LOG_FILE"
|
|
237
|
+
echo "🛑 STOP file detected. Emergency exit."
|
|
238
|
+
exit 0
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
# Check: Max time
|
|
242
|
+
CURRENT_TIME=$(date +%s)
|
|
243
|
+
ELAPSED_MINUTES=$(( (CURRENT_TIME - START_TIME) / 60 ))
|
|
244
|
+
if [ $ELAPSED_MINUTES -ge $MAX_MINUTES ]; then
|
|
245
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SAFE] Max time reached: $ELAPSED_MINUTES min" >> "$LOG_FILE"
|
|
246
|
+
echo "⏰ Max time ($MAX_MINUTES min) reached. Stopping."
|
|
247
|
+
exit 0
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
# Check: Confirmation required
|
|
251
|
+
if [ $((ITER % CONFIRM_EVERY)) -eq 0 ]; then
|
|
252
|
+
echo ""
|
|
253
|
+
echo "⏸️ Confirmation required (timeout: \${CONFIRM_TIMEOUT}s)"
|
|
254
|
+
echo -n " Continue? [y/N]: "
|
|
255
|
+
|
|
256
|
+
if read -t $CONFIRM_TIMEOUT -r REPLY; then
|
|
257
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
258
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SAFE] User declined to continue" >> "$LOG_FILE"
|
|
259
|
+
echo "🛑 User stopped the loop."
|
|
260
|
+
exit 0
|
|
261
|
+
fi
|
|
262
|
+
else
|
|
263
|
+
echo ""
|
|
264
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SAFE] Confirmation timeout" >> "$LOG_FILE"
|
|
265
|
+
echo "⏰ Confirmation timeout. Stopping for safety."
|
|
266
|
+
exit 0
|
|
267
|
+
fi
|
|
268
|
+
fi
|
|
269
|
+
|
|
270
|
+
# Execute Claude Code
|
|
271
|
+
echo "🤖 Running: $CLI_COMMAND @PROMPT.md"
|
|
272
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] Iteration $ITER started" >> "$LOG_FILE"
|
|
273
|
+
|
|
274
|
+
OUTPUT_FILE="last_output_$ITER.txt"
|
|
275
|
+
if $CLI_COMMAND @PROMPT.md > "$OUTPUT_FILE" 2>&1; then
|
|
276
|
+
cat "$OUTPUT_FILE"
|
|
277
|
+
else
|
|
278
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] CLI command failed" >> "$LOG_FILE"
|
|
279
|
+
echo "❌ CLI command failed. Check $OUTPUT_FILE"
|
|
280
|
+
exit 1
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
# Check: Output repetition
|
|
284
|
+
CURRENT_HASH=$(md5sum "$OUTPUT_FILE" 2>/dev/null | cut -d' ' -f1 || echo "")
|
|
285
|
+
if [ "$CURRENT_HASH" = "$LAST_OUTPUT_HASH" ]; then
|
|
286
|
+
SAME_OUTPUT_COUNT=$((SAME_OUTPUT_COUNT + 1))
|
|
287
|
+
if [ $SAME_OUTPUT_COUNT -ge $MAX_SAME_OUTPUT ]; then
|
|
288
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] Output repeated $SAME_OUTPUT_COUNT times" >> "$LOG_FILE"
|
|
289
|
+
echo "⚠️ Output repeated $SAME_OUTPUT_COUNT times. Likely stuck. Stopping."
|
|
290
|
+
exit 0
|
|
291
|
+
fi
|
|
292
|
+
else
|
|
293
|
+
SAME_OUTPUT_COUNT=0
|
|
294
|
+
fi
|
|
295
|
+
LAST_OUTPUT_HASH="$CURRENT_HASH"
|
|
296
|
+
|
|
297
|
+
# Check: Git diff size (if in git repo)
|
|
298
|
+
if git rev-parse --git-dir > /dev/null 2>&1; then
|
|
299
|
+
CHANGED_LINES=$(git diff --stat | tail -1 | grep -oE '[0-9]+ insertion|[0-9]+ deletion' | grep -oE '[0-9]+' | awk '{s+=$1} END {print s}' || echo "0")
|
|
300
|
+
if [ "$CHANGED_LINES" -gt "$MAX_DIFF_LINES" ]; then
|
|
301
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] Changed lines ($CHANGED_LINES) exceeds limit ($MAX_DIFF_LINES)" >> "$LOG_FILE"
|
|
302
|
+
echo "⚠️ Changed $CHANGED_LINES lines (limit: $MAX_DIFF_LINES). Please review manually."
|
|
303
|
+
echo " Run: git diff --stat"
|
|
304
|
+
exit 0
|
|
305
|
+
fi
|
|
306
|
+
fi
|
|
307
|
+
|
|
308
|
+
# Check: Exit signals in output
|
|
309
|
+
if grep -q "COMPLETION_PROMISE_MET: true" "$OUTPUT_FILE" && grep -q "EXIT_SIGNAL: true" "$OUTPUT_FILE"; then
|
|
310
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] Both exit conditions met" >> "$LOG_FILE"
|
|
311
|
+
echo "✅ Completion promise met and exit signal received. Success!"
|
|
312
|
+
exit 0
|
|
313
|
+
fi
|
|
314
|
+
|
|
315
|
+
# Cooldown
|
|
316
|
+
echo "😴 Cooldown: \${COOLDOWN_SECONDS}s..."
|
|
317
|
+
sleep $COOLDOWN_SECONDS
|
|
318
|
+
done
|
|
319
|
+
|
|
320
|
+
# Max iterations reached
|
|
321
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SAFE] Max iterations reached" >> "$LOG_FILE"
|
|
322
|
+
echo "⏰ Max iterations ($MAX_ITERS) reached. Stopping."
|
|
323
|
+
exit 0
|
|
324
|
+
`;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* 生成普通模式脚本 (Bash)
|
|
328
|
+
*/
|
|
329
|
+
function generateNormalScript(params) {
|
|
330
|
+
return `#!/bin/bash
|
|
331
|
+
# Ralph Loop - Normal Mode (Use with caution!)
|
|
332
|
+
# Generated by MCP Probe Kit
|
|
333
|
+
|
|
334
|
+
set -euo pipefail
|
|
335
|
+
|
|
336
|
+
# ============================================
|
|
337
|
+
# PARAMETERS
|
|
338
|
+
# ============================================
|
|
339
|
+
MAX_ITERS=\${MAX_ITERS:-${params.max_iterations}}
|
|
340
|
+
CLI_COMMAND=\${CLI_COMMAND:-${params.cli_command}}
|
|
341
|
+
|
|
342
|
+
echo "🚀 Ralph Loop - Normal Mode"
|
|
343
|
+
echo "⚠️ WARNING: No confirmation required. Use Ctrl+C to stop."
|
|
344
|
+
echo " Max iterations: $MAX_ITERS"
|
|
345
|
+
echo ""
|
|
346
|
+
sleep 3
|
|
347
|
+
|
|
348
|
+
ITER=0
|
|
349
|
+
LOG_FILE="ralph.log"
|
|
350
|
+
|
|
351
|
+
while [ $ITER -lt $MAX_ITERS ]; do
|
|
352
|
+
ITER=$((ITER + 1))
|
|
353
|
+
echo "🔄 Iteration $ITER / $MAX_ITERS"
|
|
354
|
+
|
|
355
|
+
if [ -f "STOP" ]; then
|
|
356
|
+
echo "🛑 STOP file detected."
|
|
357
|
+
exit 0
|
|
358
|
+
fi
|
|
359
|
+
|
|
360
|
+
OUTPUT_FILE="last_output_$ITER.txt"
|
|
361
|
+
$CLI_COMMAND @PROMPT.md | tee "$OUTPUT_FILE"
|
|
362
|
+
|
|
363
|
+
if grep -q "COMPLETION_PROMISE_MET: true" "$OUTPUT_FILE" && grep -q "EXIT_SIGNAL: true" "$OUTPUT_FILE"; then
|
|
364
|
+
echo "✅ Success!"
|
|
365
|
+
exit 0
|
|
366
|
+
fi
|
|
367
|
+
|
|
368
|
+
sleep 5
|
|
369
|
+
done
|
|
370
|
+
|
|
371
|
+
echo "⏰ Max iterations reached."
|
|
372
|
+
exit 0
|
|
373
|
+
`;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* 生成 Windows 安全模式脚本 (PowerShell)
|
|
377
|
+
*/
|
|
378
|
+
function generateSafeScriptWindows(params) {
|
|
379
|
+
return `# Ralph Loop - Safe Mode (Windows)
|
|
380
|
+
# Generated by MCP Probe Kit
|
|
381
|
+
|
|
382
|
+
$ErrorActionPreference = "Stop"
|
|
383
|
+
|
|
384
|
+
# ============================================
|
|
385
|
+
# SAFETY PARAMETERS
|
|
386
|
+
# ============================================
|
|
387
|
+
$MAX_ITERS = if ($env:MAX_ITERS) { [int]$env:MAX_ITERS } else { ${params.max_iterations} }
|
|
388
|
+
$MAX_MINUTES = if ($env:MAX_MINUTES) { [int]$env:MAX_MINUTES } else { ${params.max_minutes} }
|
|
389
|
+
$CONFIRM_EVERY = if ($env:CONFIRM_EVERY) { [int]$env:CONFIRM_EVERY } else { ${params.confirm_every} }
|
|
390
|
+
$CONFIRM_TIMEOUT = if ($env:CONFIRM_TIMEOUT) { [int]$env:CONFIRM_TIMEOUT } else { ${params.confirm_timeout} }
|
|
391
|
+
$MAX_SAME_OUTPUT = if ($env:MAX_SAME_OUTPUT) { [int]$env:MAX_SAME_OUTPUT } else { ${params.max_same_output} }
|
|
392
|
+
$MAX_DIFF_LINES = if ($env:MAX_DIFF_LINES) { [int]$env:MAX_DIFF_LINES } else { ${params.max_diff_lines} }
|
|
393
|
+
$COOLDOWN_SECONDS = if ($env:COOLDOWN_SECONDS) { [int]$env:COOLDOWN_SECONDS } else { ${params.cooldown_seconds} }
|
|
394
|
+
$CLI_COMMAND = if ($env:CLI_COMMAND) { $env:CLI_COMMAND } else { "${params.cli_command}" }
|
|
395
|
+
|
|
396
|
+
if (-not (Test-Path "PROMPT.md")) {
|
|
397
|
+
Write-Host "❌ ERROR: PROMPT.md not found" -ForegroundColor Red
|
|
398
|
+
exit 1
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
Write-Host "🚀 Ralph Loop - Safe Mode" -ForegroundColor Cyan
|
|
402
|
+
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
403
|
+
Write-Host "⚠️ Safety Limits:"
|
|
404
|
+
Write-Host " • Max iterations: $MAX_ITERS"
|
|
405
|
+
Write-Host " • Max time: $MAX_MINUTES minutes"
|
|
406
|
+
Write-Host " • Confirm every: $CONFIRM_EVERY iteration(s)"
|
|
407
|
+
Write-Host ""
|
|
408
|
+
Write-Host "💡 Emergency stop: New-Item -ItemType File -Name STOP"
|
|
409
|
+
Write-Host ""
|
|
410
|
+
Write-Host "Press Ctrl+C to cancel, or wait 5s to start..."
|
|
411
|
+
Start-Sleep -Seconds 5
|
|
412
|
+
|
|
413
|
+
$ITER = 0
|
|
414
|
+
$START_TIME = Get-Date
|
|
415
|
+
$LAST_OUTPUT_HASH = ""
|
|
416
|
+
$SAME_OUTPUT_COUNT = 0
|
|
417
|
+
$LOG_FILE = "ralph.log"
|
|
418
|
+
|
|
419
|
+
Add-Content -Path $LOG_FILE -Value "[$((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))] [INFO] Loop started"
|
|
420
|
+
|
|
421
|
+
while ($ITER -lt $MAX_ITERS) {
|
|
422
|
+
$ITER++
|
|
423
|
+
Write-Host ""
|
|
424
|
+
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
425
|
+
Write-Host "🔄 Iteration $ITER / $MAX_ITERS" -ForegroundColor Yellow
|
|
426
|
+
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
427
|
+
|
|
428
|
+
if (Test-Path "STOP") {
|
|
429
|
+
Add-Content -Path $LOG_FILE -Value "[$((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))] [SAFE] STOP file detected"
|
|
430
|
+
Write-Host "🛑 STOP file detected. Emergency exit." -ForegroundColor Red
|
|
431
|
+
exit 0
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
$ELAPSED_MINUTES = ((Get-Date) - $START_TIME).TotalMinutes
|
|
435
|
+
if ($ELAPSED_MINUTES -ge $MAX_MINUTES) {
|
|
436
|
+
Add-Content -Path $LOG_FILE -Value "[$((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))] [SAFE] Max time reached"
|
|
437
|
+
Write-Host "⏰ Max time reached. Stopping." -ForegroundColor Yellow
|
|
438
|
+
exit 0
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if ($ITER % $CONFIRM_EVERY -eq 0) {
|
|
442
|
+
Write-Host ""
|
|
443
|
+
Write-Host "⏸️ Confirmation required" -ForegroundColor Yellow
|
|
444
|
+
$response = Read-Host " Continue? [y/N]"
|
|
445
|
+
if ($response -notmatch '^[Yy]$') {
|
|
446
|
+
Add-Content -Path $LOG_FILE -Value "[$((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))] [SAFE] User declined"
|
|
447
|
+
Write-Host "🛑 User stopped the loop." -ForegroundColor Red
|
|
448
|
+
exit 0
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
Write-Host "🤖 Running: $CLI_COMMAND @PROMPT.md"
|
|
453
|
+
$OUTPUT_FILE = "last_output_$ITER.txt"
|
|
454
|
+
& $CLI_COMMAND "@PROMPT.md" | Tee-Object -FilePath $OUTPUT_FILE
|
|
455
|
+
|
|
456
|
+
$CURRENT_HASH = (Get-FileHash -Path $OUTPUT_FILE -Algorithm MD5).Hash
|
|
457
|
+
if ($CURRENT_HASH -eq $LAST_OUTPUT_HASH) {
|
|
458
|
+
$SAME_OUTPUT_COUNT++
|
|
459
|
+
if ($SAME_OUTPUT_COUNT -ge $MAX_SAME_OUTPUT) {
|
|
460
|
+
Write-Host "⚠️ Output repeated. Likely stuck. Stopping." -ForegroundColor Yellow
|
|
461
|
+
exit 0
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
464
|
+
$SAME_OUTPUT_COUNT = 0
|
|
465
|
+
}
|
|
466
|
+
$LAST_OUTPUT_HASH = $CURRENT_HASH
|
|
467
|
+
|
|
468
|
+
$content = Get-Content $OUTPUT_FILE -Raw
|
|
469
|
+
if ($content -match "COMPLETION_PROMISE_MET: true" -and $content -match "EXIT_SIGNAL: true") {
|
|
470
|
+
Write-Host "✅ Success!" -ForegroundColor Green
|
|
471
|
+
exit 0
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
Write-Host "😴 Cooldown: \${COOLDOWN_SECONDS}s..."
|
|
475
|
+
Start-Sleep -Seconds $COOLDOWN_SECONDS
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
Write-Host "⏰ Max iterations reached." -ForegroundColor Yellow
|
|
479
|
+
exit 0
|
|
480
|
+
`;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* 生成执行指南
|
|
484
|
+
*/
|
|
485
|
+
function generateGuide(params, isWindows) {
|
|
486
|
+
const scriptName = isWindows ? "ralph_loop_safe.ps1" : "ralph_loop_safe.sh";
|
|
487
|
+
const scriptCmd = isWindows ? `powershell -ExecutionPolicy Bypass -File ${scriptName}` : `./${scriptName}`;
|
|
488
|
+
const chmodCmd = isWindows ? "" : `chmod +x ${scriptName}\n`;
|
|
489
|
+
return `# 🚀 Ralph Loop Setup Complete!
|
|
490
|
+
|
|
491
|
+
## 📂 Generated Files
|
|
492
|
+
|
|
493
|
+
\`.ralph/\` directory structure:
|
|
494
|
+
- \`PROMPT.md\` - Loop prompt with goal and rules
|
|
495
|
+
- \`@fix_plan.md\` - Task breakdown (updated by agent)
|
|
496
|
+
- \`PROGRESS.md\` - Iteration log (updated by agent)
|
|
497
|
+
- \`${scriptName}\` - Safe mode script (default)
|
|
498
|
+
- \`ralph_loop.sh\` - Normal mode script (optional, use with caution)
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## 🎯 Goal
|
|
503
|
+
|
|
504
|
+
${params.goal}
|
|
505
|
+
|
|
506
|
+
**Completion Promise**: ${params.completion_promise}
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## 🛡️ Safety Configuration (Mode: ${params.mode})
|
|
511
|
+
|
|
512
|
+
| Parameter | Value | Description |
|
|
513
|
+
|-----------|-------|-------------|
|
|
514
|
+
| Max Iterations | ${params.max_iterations} | Hard limit on loop count |
|
|
515
|
+
| Max Minutes | ${params.max_minutes} | Hard limit on runtime |
|
|
516
|
+
| Confirm Every | ${params.confirm_every} | Require confirmation every N iterations |
|
|
517
|
+
| Confirm Timeout | ${params.confirm_timeout}s | Auto-stop if no response |
|
|
518
|
+
| Max Same Output | ${params.max_same_output} | Stop if output repeats N times |
|
|
519
|
+
| Max Diff Lines | ${params.max_diff_lines} | Stop if changes exceed N lines |
|
|
520
|
+
| Cooldown | ${params.cooldown_seconds}s | Pause between iterations |
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## 🚀 How to Start
|
|
525
|
+
|
|
526
|
+
### 1. Create .ralph directory
|
|
527
|
+
\`\`\`bash
|
|
528
|
+
mkdir -p .ralph
|
|
529
|
+
cd .ralph
|
|
530
|
+
\`\`\`
|
|
531
|
+
|
|
532
|
+
### 2. Copy files
|
|
533
|
+
Copy the generated content below into respective files:
|
|
534
|
+
- \`PROMPT.md\`
|
|
535
|
+
- \`@fix_plan.md\`
|
|
536
|
+
- \`PROGRESS.md\`
|
|
537
|
+
- \`${scriptName}\`
|
|
538
|
+
|
|
539
|
+
### 3. Make script executable${isWindows ? "" : " (Linux/Mac)"}
|
|
540
|
+
\`\`\`bash
|
|
541
|
+
${chmodCmd}\`\`\`
|
|
542
|
+
|
|
543
|
+
### 4. Run the loop
|
|
544
|
+
\`\`\`bash
|
|
545
|
+
${scriptCmd}
|
|
546
|
+
\`\`\`
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## 🛑 How to Stop
|
|
551
|
+
|
|
552
|
+
### Emergency Stop
|
|
553
|
+
\`\`\`bash
|
|
554
|
+
touch .ralph/STOP
|
|
555
|
+
\`\`\`
|
|
556
|
+
The loop will exit immediately on next check.
|
|
557
|
+
|
|
558
|
+
### Manual Stop
|
|
559
|
+
Press \`Ctrl+C\` in the terminal.
|
|
560
|
+
|
|
561
|
+
### Timeout Stop
|
|
562
|
+
Don't respond to confirmation prompt (waits ${params.confirm_timeout}s then stops).
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
## ⚙️ How to Adjust Parameters
|
|
567
|
+
|
|
568
|
+
Override via environment variables:
|
|
569
|
+
|
|
570
|
+
\`\`\`bash
|
|
571
|
+
# Example: Increase max iterations to 15
|
|
572
|
+
${isWindows ? "$env:MAX_ITERS=15" : "MAX_ITERS=15"} ${scriptCmd}
|
|
573
|
+
|
|
574
|
+
# Example: Disable confirmation (not recommended!)
|
|
575
|
+
${isWindows ? "$env:CONFIRM_EVERY=999" : "CONFIRM_EVERY=999"} ${scriptCmd}
|
|
576
|
+
|
|
577
|
+
# Example: Use different CLI command
|
|
578
|
+
${isWindows ? "$env:CLI_COMMAND='claude'" : "CLI_COMMAND='claude'"} ${scriptCmd}
|
|
579
|
+
\`\`\`
|
|
580
|
+
|
|
581
|
+
Available overrides:
|
|
582
|
+
- \`MAX_ITERS\`
|
|
583
|
+
- \`MAX_MINUTES\`
|
|
584
|
+
- \`CONFIRM_EVERY\`
|
|
585
|
+
- \`CONFIRM_TIMEOUT\`
|
|
586
|
+
- \`MAX_SAME_OUTPUT\`
|
|
587
|
+
- \`MAX_DIFF_LINES\`
|
|
588
|
+
- \`COOLDOWN_SECONDS\`
|
|
589
|
+
- \`CLI_COMMAND\`
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## 📊 How to Monitor
|
|
594
|
+
|
|
595
|
+
### View logs
|
|
596
|
+
\`\`\`bash
|
|
597
|
+
tail -f .ralph/ralph.log
|
|
598
|
+
\`\`\`
|
|
599
|
+
|
|
600
|
+
### Check progress
|
|
601
|
+
\`\`\`bash
|
|
602
|
+
cat .ralph/PROGRESS.md
|
|
603
|
+
\`\`\`
|
|
604
|
+
|
|
605
|
+
### Check tasks
|
|
606
|
+
\`\`\`bash
|
|
607
|
+
cat .ralph/@fix_plan.md
|
|
608
|
+
\`\`\`
|
|
609
|
+
|
|
610
|
+
### View last output
|
|
611
|
+
\`\`\`bash
|
|
612
|
+
cat .ralph/last_output_*.txt
|
|
613
|
+
\`\`\`
|
|
614
|
+
|
|
615
|
+
---
|
|
616
|
+
|
|
617
|
+
## 💡 Tips
|
|
618
|
+
|
|
619
|
+
1. **First iteration is critical**: The agent will identify the correct test command for your project
|
|
620
|
+
2. **Watch for repetition**: If output repeats ${params.max_same_output} times, loop auto-stops
|
|
621
|
+
3. **Review large changes**: If changes exceed ${params.max_diff_lines} lines, loop stops for manual review
|
|
622
|
+
4. **Use git**: Loop works best in git repos (tracks changes, can auto-backup)
|
|
623
|
+
5. **Start small**: Default limits are conservative - adjust after successful runs
|
|
624
|
+
|
|
625
|
+
---
|
|
626
|
+
|
|
627
|
+
## ⚠️ Warnings
|
|
628
|
+
|
|
629
|
+
- **Cost**: Each iteration calls the LLM API. Monitor usage!
|
|
630
|
+
- **Normal mode**: Use only when you're confident. No confirmations = potential runaway.
|
|
631
|
+
- **Test command**: Wrong test command = wasted iterations. Verify in first run.
|
|
632
|
+
- **Background execution**: Not recommended. Always run in foreground with TTY.
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
## 🔗 Integration with Other Tools
|
|
637
|
+
|
|
638
|
+
### Recommended workflow:
|
|
639
|
+
|
|
640
|
+
1. **Generate context** (optional but recommended):
|
|
641
|
+
\`\`\`bash
|
|
642
|
+
${params.cli_command} "使用 init_project_context 生成项目文档"
|
|
643
|
+
\`\`\`
|
|
644
|
+
|
|
645
|
+
2. **Generate feature spec** (if building new feature):
|
|
646
|
+
\`\`\`bash
|
|
647
|
+
${params.cli_command} "使用 start_feature 生成功能规格,goal='${params.goal}'"
|
|
648
|
+
\`\`\`
|
|
649
|
+
|
|
650
|
+
3. **Start Ralph Loop**:
|
|
651
|
+
\`\`\`bash
|
|
652
|
+
cd .ralph
|
|
653
|
+
${scriptCmd}
|
|
654
|
+
\`\`\`
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
658
|
+
*Generated by MCP Probe Kit - start_ralph v1.0*
|
|
659
|
+
`;
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* start_ralph 主函数
|
|
663
|
+
*/
|
|
664
|
+
export async function startRalph(args) {
|
|
665
|
+
try {
|
|
666
|
+
const parsedArgs = parseArgs(args, {
|
|
667
|
+
defaultValues: DEFAULTS,
|
|
668
|
+
primaryField: "goal",
|
|
669
|
+
fieldAliases: {
|
|
670
|
+
goal: ["目标", "任务", "task"],
|
|
671
|
+
mode: ["模式"],
|
|
672
|
+
completion_promise: ["完成条件", "退出条件"],
|
|
673
|
+
test_command: ["测试命令"],
|
|
674
|
+
cli_command: ["命令", "cli"],
|
|
675
|
+
max_iterations: ["最大迭代", "max_iters"],
|
|
676
|
+
max_minutes: ["最大时间", "max_time"],
|
|
677
|
+
confirm_every: ["确认频率"],
|
|
678
|
+
confirm_timeout: ["确认超时"],
|
|
679
|
+
max_same_output: ["最大重复"],
|
|
680
|
+
max_diff_lines: ["最大变更行数"],
|
|
681
|
+
cooldown_seconds: ["冷却时间"],
|
|
682
|
+
},
|
|
683
|
+
});
|
|
684
|
+
const goal = getString(parsedArgs.goal) || "Complete the development task";
|
|
685
|
+
const mode = getString(parsedArgs.mode) || DEFAULTS.mode;
|
|
686
|
+
const completionPromise = getString(parsedArgs.completion_promise) || DEFAULTS.completion_promise;
|
|
687
|
+
const testCommand = getString(parsedArgs.test_command) || DEFAULTS.test_command;
|
|
688
|
+
const cliCommand = getString(parsedArgs.cli_command) || DEFAULTS.cli_command;
|
|
689
|
+
const params = {
|
|
690
|
+
goal,
|
|
691
|
+
mode,
|
|
692
|
+
completion_promise: completionPromise,
|
|
693
|
+
test_command: testCommand,
|
|
694
|
+
cli_command: cliCommand,
|
|
695
|
+
max_iterations: getNumber(parsedArgs.max_iterations) ?? DEFAULTS.max_iterations,
|
|
696
|
+
max_minutes: getNumber(parsedArgs.max_minutes) ?? DEFAULTS.max_minutes,
|
|
697
|
+
confirm_every: getNumber(parsedArgs.confirm_every) ?? DEFAULTS.confirm_every,
|
|
698
|
+
confirm_timeout: getNumber(parsedArgs.confirm_timeout) ?? DEFAULTS.confirm_timeout,
|
|
699
|
+
max_same_output: getNumber(parsedArgs.max_same_output) ?? DEFAULTS.max_same_output,
|
|
700
|
+
max_diff_lines: getNumber(parsedArgs.max_diff_lines) ?? DEFAULTS.max_diff_lines,
|
|
701
|
+
cooldown_seconds: getNumber(parsedArgs.cooldown_seconds) ?? DEFAULTS.cooldown_seconds,
|
|
702
|
+
};
|
|
703
|
+
// 检测操作系统
|
|
704
|
+
const isWindows = process.platform === "win32";
|
|
705
|
+
// 生成所有文件内容
|
|
706
|
+
const promptMd = generatePromptTemplate(params.goal, params.completion_promise, params.test_command);
|
|
707
|
+
const fixPlanMd = generateFixPlanTemplate(params.goal);
|
|
708
|
+
const progressMd = generateProgressTemplate();
|
|
709
|
+
const safeScript = isWindows
|
|
710
|
+
? generateSafeScriptWindows(params)
|
|
711
|
+
: generateSafeScript(params);
|
|
712
|
+
const normalScript = generateNormalScript(params);
|
|
713
|
+
const guide = generateGuide(params, isWindows);
|
|
714
|
+
// 组装输出
|
|
715
|
+
const scriptExt = isWindows ? "ps1" : "sh";
|
|
716
|
+
const output = `${guide}
|
|
717
|
+
|
|
718
|
+
---
|
|
719
|
+
|
|
720
|
+
## 📄 File Contents
|
|
721
|
+
|
|
722
|
+
### 1. PROMPT.md
|
|
723
|
+
\`\`\`markdown
|
|
724
|
+
${promptMd}
|
|
725
|
+
\`\`\`
|
|
726
|
+
|
|
727
|
+
---
|
|
728
|
+
|
|
729
|
+
### 2. @fix_plan.md
|
|
730
|
+
\`\`\`markdown
|
|
731
|
+
${fixPlanMd}
|
|
732
|
+
\`\`\`
|
|
733
|
+
|
|
734
|
+
---
|
|
735
|
+
|
|
736
|
+
### 3. PROGRESS.md
|
|
737
|
+
\`\`\`markdown
|
|
738
|
+
${progressMd}
|
|
739
|
+
\`\`\`
|
|
740
|
+
|
|
741
|
+
---
|
|
742
|
+
|
|
743
|
+
### 4. ralph_loop_safe.${scriptExt} (Safe Mode - Recommended)
|
|
744
|
+
\`\`\`${isWindows ? 'powershell' : 'bash'}
|
|
745
|
+
${safeScript}
|
|
746
|
+
\`\`\`
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
### 5. ralph_loop.sh (Normal Mode - Use with Caution)
|
|
751
|
+
\`\`\`bash
|
|
752
|
+
${normalScript}
|
|
753
|
+
\`\`\`
|
|
754
|
+
|
|
755
|
+
---
|
|
756
|
+
|
|
757
|
+
## ✅ Next Steps
|
|
758
|
+
|
|
759
|
+
1. Create \`.ralph/\` directory
|
|
760
|
+
2. Copy each file content above into respective files
|
|
761
|
+
3. Make scripts executable (if on Linux/Mac)
|
|
762
|
+
4. Review PROMPT.md and adjust if needed
|
|
763
|
+
5. Run \`ralph_loop_safe.${scriptExt}\`
|
|
764
|
+
6. Monitor progress and logs
|
|
765
|
+
|
|
766
|
+
**Happy coding! 🚀**
|
|
767
|
+
`;
|
|
768
|
+
return {
|
|
769
|
+
content: [{ type: "text", text: output }],
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
catch (error) {
|
|
773
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
774
|
+
return {
|
|
775
|
+
content: [{ type: "text", text: `❌ start_ralph 执行失败: ${errorMsg}` }],
|
|
776
|
+
isError: true,
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
}
|