coder-config 0.41.17 → 0.41.21

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.
@@ -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-CLOEO79k.js"></script>
22
+ <script type="module" crossorigin src="/assets/index-CySxCEgN.js"></script>
23
23
  <link rel="stylesheet" crossorigin href="/assets/index-DN9CerwX.css">
24
24
  </head>
25
25
  <body>
@@ -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
- const hooksDir = path.join(os.homedir(), '.claude', 'hooks');
246
- const stopHookPath = path.join(hooksDir, 'ralph-loop-stop.sh');
247
- const prepromptHookPath = path.join(hooksDir, 'ralph-loop-preprompt.sh');
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
- hooksDir,
251
- dirExists: fs.existsSync(hooksDir),
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(stopHookPath)
268
+ path: officialHookExists ? stopHookPath : customStopHookPath,
269
+ exists: officialHookExists || fs.existsSync(customStopHookPath)
255
270
  },
256
271
  prepromptHook: {
257
- path: prepromptHookPath,
258
- exists: fs.existsSync(prepromptHookPath)
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 hooksDir = path.join(os.homedir(), '.claude', 'hooks');
270
- const coderConfigDir = manager ? path.dirname(manager.getLoopsPath()) : path.join(os.homedir(), '.coder-config');
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: 'Loop hooks installed successfully',
398
- stopHook: stopHookPath,
399
- prepromptHook: prepromptHookPath
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 = {