coder-config 0.41.17 → 0.41.19
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/lib/constants.js +1 -1
- package/lib/loops.js +18 -7
- package/package.json +1 -1
- package/ui/dist/assets/{index-CLOEO79k.js → index-BtHQh9qm.js} +133 -133
- package/ui/dist/index.html +1 -1
- package/ui/routes/loops.js +47 -143
package/ui/dist/index.html
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
<!-- PWA Manifest -->
|
|
21
21
|
<link rel="manifest" href="/manifest.json">
|
|
22
|
-
<script type="module" crossorigin src="/assets/index-
|
|
22
|
+
<script type="module" crossorigin src="/assets/index-BtHQh9qm.js"></script>
|
|
23
23
|
<link rel="stylesheet" crossorigin href="/assets/index-DN9CerwX.css">
|
|
24
24
|
</head>
|
|
25
25
|
<body>
|
package/ui/routes/loops.js
CHANGED
|
@@ -61,7 +61,7 @@ function getLoop(manager, id) {
|
|
|
61
61
|
*/
|
|
62
62
|
function createLoop(manager, body) {
|
|
63
63
|
if (!manager) return { error: 'Manager not available' };
|
|
64
|
-
const { task, name, workstreamId, projectPath } = body;
|
|
64
|
+
const { task, name, workstreamId, projectPath, maxIterations, completionPromise } = body;
|
|
65
65
|
|
|
66
66
|
if (!task) {
|
|
67
67
|
return { error: 'Task description is required' };
|
|
@@ -70,7 +70,9 @@ function createLoop(manager, body) {
|
|
|
70
70
|
const loop = manager.loopCreate(task, {
|
|
71
71
|
name,
|
|
72
72
|
workstreamId,
|
|
73
|
-
projectPath
|
|
73
|
+
projectPath,
|
|
74
|
+
maxIterations: maxIterations || undefined,
|
|
75
|
+
completionPromise: completionPromise || undefined
|
|
74
76
|
});
|
|
75
77
|
|
|
76
78
|
if (!loop) {
|
|
@@ -239,23 +241,37 @@ function recordIteration(manager, id, iteration) {
|
|
|
239
241
|
}
|
|
240
242
|
|
|
241
243
|
/**
|
|
242
|
-
* Check if loop hooks are installed
|
|
244
|
+
* Check if loop hooks are installed (official ralph-loop plugin)
|
|
243
245
|
*/
|
|
244
246
|
function getLoopHookStatus() {
|
|
245
|
-
|
|
246
|
-
const
|
|
247
|
-
const
|
|
247
|
+
// Check for official ralph-loop plugin
|
|
248
|
+
const pluginsDir = path.join(os.homedir(), '.claude', 'plugins', 'marketplaces');
|
|
249
|
+
const officialPluginPath = path.join(pluginsDir, 'claude-plugins-official', 'plugins', 'ralph-loop');
|
|
250
|
+
const stopHookPath = path.join(officialPluginPath, 'hooks', 'stop-hook.sh');
|
|
251
|
+
|
|
252
|
+
// Also check custom hooks dir for backwards compatibility
|
|
253
|
+
const customHooksDir = path.join(os.homedir(), '.claude', 'hooks');
|
|
254
|
+
const customStopHookPath = path.join(customHooksDir, 'ralph-loop-stop.sh');
|
|
255
|
+
const customPrepromptHookPath = path.join(customHooksDir, 'ralph-loop-preprompt.sh');
|
|
256
|
+
|
|
257
|
+
const officialPluginExists = fs.existsSync(officialPluginPath);
|
|
258
|
+
const officialHookExists = fs.existsSync(stopHookPath);
|
|
248
259
|
|
|
249
260
|
const status = {
|
|
250
|
-
|
|
251
|
-
|
|
261
|
+
// Official plugin is preferred
|
|
262
|
+
usingOfficialPlugin: officialPluginExists,
|
|
263
|
+
officialPlugin: {
|
|
264
|
+
path: officialPluginPath,
|
|
265
|
+
exists: officialPluginExists
|
|
266
|
+
},
|
|
252
267
|
stopHook: {
|
|
253
|
-
path: stopHookPath,
|
|
254
|
-
exists: fs.existsSync(
|
|
268
|
+
path: officialHookExists ? stopHookPath : customStopHookPath,
|
|
269
|
+
exists: officialHookExists || fs.existsSync(customStopHookPath)
|
|
255
270
|
},
|
|
256
271
|
prepromptHook: {
|
|
257
|
-
|
|
258
|
-
|
|
272
|
+
// Official plugin doesn't need preprompt hook
|
|
273
|
+
path: customPrepromptHookPath,
|
|
274
|
+
exists: officialPluginExists || fs.existsSync(customPrepromptHookPath)
|
|
259
275
|
}
|
|
260
276
|
};
|
|
261
277
|
|
|
@@ -263,144 +279,32 @@ function getLoopHookStatus() {
|
|
|
263
279
|
}
|
|
264
280
|
|
|
265
281
|
/**
|
|
266
|
-
* Install loop hooks
|
|
282
|
+
* Install loop hooks (or verify official plugin is installed)
|
|
267
283
|
*/
|
|
268
284
|
function installLoopHooks(manager) {
|
|
269
|
-
const
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
try {
|
|
273
|
-
if (!fs.existsSync(hooksDir)) {
|
|
274
|
-
fs.mkdirSync(hooksDir, { recursive: true });
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Stop hook
|
|
278
|
-
const stopHookContent = `#!/bin/bash
|
|
279
|
-
# Ralph Loop continuation hook
|
|
280
|
-
# Called after each Claude response
|
|
281
|
-
|
|
282
|
-
LOOP_ID="\$CODER_LOOP_ID"
|
|
283
|
-
if [[ -z "\$LOOP_ID" ]]; then
|
|
284
|
-
exit 0
|
|
285
|
-
fi
|
|
286
|
-
|
|
287
|
-
STATE_FILE="\$HOME/.coder-config/loops/\$LOOP_ID/state.json"
|
|
288
|
-
if [[ ! -f "\$STATE_FILE" ]]; then
|
|
289
|
-
exit 0
|
|
290
|
-
fi
|
|
291
|
-
|
|
292
|
-
# Check if loop is still active
|
|
293
|
-
STATUS=$(jq -r '.status' "\$STATE_FILE")
|
|
294
|
-
if [[ "\$STATUS" != "running" ]]; then
|
|
295
|
-
exit 0
|
|
296
|
-
fi
|
|
297
|
-
|
|
298
|
-
# Check budget limits
|
|
299
|
-
CURRENT_ITER=$(jq -r '.iterations.current' "\$STATE_FILE")
|
|
300
|
-
MAX_ITER=$(jq -r '.iterations.max' "\$STATE_FILE")
|
|
301
|
-
CURRENT_COST=$(jq -r '.budget.currentCost' "\$STATE_FILE")
|
|
302
|
-
MAX_COST=$(jq -r '.budget.maxCost' "\$STATE_FILE")
|
|
303
|
-
|
|
304
|
-
if (( CURRENT_ITER >= MAX_ITER )); then
|
|
305
|
-
echo "Loop paused: max iterations reached (\$MAX_ITER)"
|
|
306
|
-
jq '.status = "paused" | .pauseReason = "max_iterations"' "\$STATE_FILE" > tmp && mv tmp "\$STATE_FILE"
|
|
307
|
-
exit 0
|
|
308
|
-
fi
|
|
309
|
-
|
|
310
|
-
if (( $(echo "\$CURRENT_COST >= \$MAX_COST" | bc -l) )); then
|
|
311
|
-
echo "Loop paused: budget exceeded (\$\$MAX_COST)"
|
|
312
|
-
jq '.status = "paused" | .pauseReason = "budget"' "\$STATE_FILE" > tmp && mv tmp "\$STATE_FILE"
|
|
313
|
-
exit 0
|
|
314
|
-
fi
|
|
315
|
-
|
|
316
|
-
# Update iteration count
|
|
317
|
-
jq ".iterations.current = $((CURRENT_ITER + 1))" "\$STATE_FILE" > tmp && mv tmp "\$STATE_FILE"
|
|
318
|
-
|
|
319
|
-
# Check if task is complete (Claude sets this flag)
|
|
320
|
-
PHASE=$(jq -r '.phase' "\$STATE_FILE")
|
|
321
|
-
TASK_COMPLETE=$(jq -r '.taskComplete // false' "\$STATE_FILE")
|
|
322
|
-
|
|
323
|
-
if [[ "\$TASK_COMPLETE" == "true" ]]; then
|
|
324
|
-
jq '.status = "completed" | .completedAt = now' "\$STATE_FILE" > tmp && mv tmp "\$STATE_FILE"
|
|
325
|
-
echo "Loop completed successfully!"
|
|
326
|
-
exit 0
|
|
327
|
-
fi
|
|
328
|
-
|
|
329
|
-
# Continue loop - output continuation prompt
|
|
330
|
-
PHASE_PROMPT=""
|
|
331
|
-
case "\$PHASE" in
|
|
332
|
-
"clarify")
|
|
333
|
-
PHASE_PROMPT="Continue clarifying requirements. If requirements are clear, advance to planning phase by setting phase='plan'."
|
|
334
|
-
;;
|
|
335
|
-
"plan")
|
|
336
|
-
PHASE_PROMPT="Continue developing the implementation plan. When plan is complete and approved, advance to execution phase."
|
|
337
|
-
;;
|
|
338
|
-
"execute")
|
|
339
|
-
PHASE_PROMPT="Continue executing the plan. When task is complete, set taskComplete=true."
|
|
340
|
-
;;
|
|
341
|
-
esac
|
|
342
|
-
|
|
343
|
-
echo ""
|
|
344
|
-
echo "---"
|
|
345
|
-
echo "[Ralph Loop iteration $((CURRENT_ITER + 1))/\$MAX_ITER]"
|
|
346
|
-
echo "\$PHASE_PROMPT"
|
|
347
|
-
echo "---"
|
|
348
|
-
`;
|
|
349
|
-
|
|
350
|
-
const stopHookPath = path.join(hooksDir, 'ralph-loop-stop.sh');
|
|
351
|
-
fs.writeFileSync(stopHookPath, stopHookContent);
|
|
352
|
-
fs.chmodSync(stopHookPath, '755');
|
|
353
|
-
|
|
354
|
-
// Pre-prompt hook
|
|
355
|
-
const prepromptHookContent = `#!/bin/bash
|
|
356
|
-
# Ralph Loop context injection
|
|
357
|
-
|
|
358
|
-
LOOP_ID="\$CODER_LOOP_ID"
|
|
359
|
-
if [[ -z "\$LOOP_ID" ]]; then
|
|
360
|
-
exit 0
|
|
361
|
-
fi
|
|
362
|
-
|
|
363
|
-
STATE_FILE="\$HOME/.coder-config/loops/\$LOOP_ID/state.json"
|
|
364
|
-
PLAN_FILE="\$HOME/.coder-config/loops/\$LOOP_ID/plan.md"
|
|
365
|
-
CLARIFY_FILE="\$HOME/.coder-config/loops/\$LOOP_ID/clarifications.md"
|
|
366
|
-
|
|
367
|
-
if [[ ! -f "\$STATE_FILE" ]]; then
|
|
368
|
-
exit 0
|
|
369
|
-
fi
|
|
370
|
-
|
|
371
|
-
echo "<ralph-loop-context>"
|
|
372
|
-
echo "Loop: $(jq -r '.name' "\$STATE_FILE")"
|
|
373
|
-
echo "Phase: $(jq -r '.phase' "\$STATE_FILE")"
|
|
374
|
-
echo "Iteration: $(jq -r '.iterations.current' "\$STATE_FILE")/$(jq -r '.iterations.max' "\$STATE_FILE")"
|
|
375
|
-
|
|
376
|
-
if [[ -f "\$CLARIFY_FILE" ]]; then
|
|
377
|
-
echo ""
|
|
378
|
-
echo "## Clarifications"
|
|
379
|
-
cat "\$CLARIFY_FILE"
|
|
380
|
-
fi
|
|
381
|
-
|
|
382
|
-
if [[ -f "\$PLAN_FILE" ]]; then
|
|
383
|
-
echo ""
|
|
384
|
-
echo "## Plan"
|
|
385
|
-
cat "\$PLAN_FILE"
|
|
386
|
-
fi
|
|
387
|
-
|
|
388
|
-
echo "</ralph-loop-context>"
|
|
389
|
-
`;
|
|
390
|
-
|
|
391
|
-
const prepromptHookPath = path.join(hooksDir, 'ralph-loop-preprompt.sh');
|
|
392
|
-
fs.writeFileSync(prepromptHookPath, prepromptHookContent);
|
|
393
|
-
fs.chmodSync(prepromptHookPath, '755');
|
|
285
|
+
const pluginsDir = path.join(os.homedir(), '.claude', 'plugins', 'marketplaces');
|
|
286
|
+
const officialPluginPath = path.join(pluginsDir, 'claude-plugins-official', 'plugins', 'ralph-loop');
|
|
394
287
|
|
|
288
|
+
// Check if official plugin is already installed
|
|
289
|
+
if (fs.existsSync(officialPluginPath)) {
|
|
395
290
|
return {
|
|
396
291
|
success: true,
|
|
397
|
-
message: '
|
|
398
|
-
|
|
399
|
-
|
|
292
|
+
message: 'Official ralph-loop plugin is already installed',
|
|
293
|
+
usingOfficialPlugin: true,
|
|
294
|
+
pluginPath: officialPluginPath,
|
|
295
|
+
note: 'Loops use the /ralph-loop command from the official claude-plugins-official marketplace'
|
|
400
296
|
};
|
|
401
|
-
} catch (e) {
|
|
402
|
-
return { error: e.message };
|
|
403
297
|
}
|
|
298
|
+
|
|
299
|
+
// Suggest installing the official plugin
|
|
300
|
+
return {
|
|
301
|
+
success: false,
|
|
302
|
+
error: 'Official ralph-loop plugin not found',
|
|
303
|
+
suggestion: 'Install the claude-plugins-official marketplace to get the ralph-loop plugin:\n' +
|
|
304
|
+
' 1. Add marketplace: coder-config marketplace add https://github.com/anthropics/claude-plugins-official\n' +
|
|
305
|
+
' 2. Or manually clone: git clone https://github.com/anthropics/claude-plugins-official ~/.claude/plugins/marketplaces/claude-plugins-official',
|
|
306
|
+
note: 'The official plugin provides /ralph-loop command with stop-hook for autonomous loops'
|
|
307
|
+
};
|
|
404
308
|
}
|
|
405
309
|
|
|
406
310
|
module.exports = {
|