opencode-auto-loop 0.1.5 → 0.1.6
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/commands/auto-loop.md +5 -1
- package/package.json +1 -1
- package/skills/auto-loop/SKILL.md +10 -0
- package/skills/auto-loop-help/SKILL.md +9 -0
- package/src/index.ts +65 -23
package/commands/auto-loop.md
CHANGED
|
@@ -4,20 +4,24 @@ description: "Start Auto Loop - auto-continues until task completion. Use: /auto
|
|
|
4
4
|
|
|
5
5
|
# Auto Loop
|
|
6
6
|
|
|
7
|
-
Parse `$ARGUMENTS` for the task description and
|
|
7
|
+
Parse `$ARGUMENTS` for the task description and optional flags:
|
|
8
8
|
|
|
9
9
|
- If `$ARGUMENTS` contains `--max <number>`, extract that number as **maxIterations** and remove it from the task string.
|
|
10
10
|
- Otherwise, use **maxIterations**: 25
|
|
11
|
+
- If `$ARGUMENTS` contains `--ralph`, set **forceLoop** to `true` and remove it from the task string. Force mode ignores all completion signals and runs for the full maxIterations.
|
|
11
12
|
|
|
12
13
|
Invoke the `auto-loop` tool with:
|
|
13
14
|
|
|
14
15
|
- **task**: the extracted task description
|
|
15
16
|
- **maxIterations**: the extracted or default value
|
|
17
|
+
- **forceLoop**: `true` if `--ralph` was present, omit otherwise
|
|
16
18
|
|
|
17
19
|
Examples:
|
|
18
20
|
- `/auto-loop Build a REST API` → task="Build a REST API", maxIterations=25
|
|
19
21
|
- `/auto-loop Build a REST API --max 50` → task="Build a REST API", maxIterations=50
|
|
20
22
|
- `/auto-loop --max 10 Fix all lint errors` → task="Fix all lint errors", maxIterations=10
|
|
23
|
+
- `/auto-loop --ralph Fix all lint errors` → task="Fix all lint errors", maxIterations=25, forceLoop=true
|
|
24
|
+
- `/auto-loop --ralph --max 10 Fix all lint errors` → task="Fix all lint errors", maxIterations=10, forceLoop=true
|
|
21
25
|
|
|
22
26
|
After the tool confirms the loop is active, **immediately begin working on the task**. Do not just acknowledge — start doing the work right away.
|
|
23
27
|
|
package/package.json
CHANGED
|
@@ -78,6 +78,16 @@ The loop can only be stopped by:
|
|
|
78
78
|
2. Max iterations reached
|
|
79
79
|
3. User running `/cancel-auto-loop`
|
|
80
80
|
|
|
81
|
+
## Force Mode (--ralph)
|
|
82
|
+
|
|
83
|
+
When started with `--ralph`, the loop ignores ALL completion signals (`<promise>DONE</promise>`, `STATUS: COMPLETE`) and runs for the full iteration count. In force mode:
|
|
84
|
+
- You do NOT need to output `STATUS:` lines or the DONE signal
|
|
85
|
+
- The loop will continue for all iterations regardless
|
|
86
|
+
- Focus on making steady progress each iteration
|
|
87
|
+
- Still output `## Completed` and `## Next Steps` sections so the plugin can track progress
|
|
88
|
+
|
|
89
|
+
Example: `/auto-loop --ralph --max 10 Continue the refactoring task`
|
|
90
|
+
|
|
81
91
|
## Checking Status
|
|
82
92
|
|
|
83
93
|
Check current iteration and progress:
|
|
@@ -19,6 +19,15 @@ Example:
|
|
|
19
19
|
|
|
20
20
|
The AI will work on your task and automatically continue until completion.
|
|
21
21
|
|
|
22
|
+
### `/auto-loop <task> --ralph`
|
|
23
|
+
Force mode: ignore all completion signals and run for the full iteration count. Useful when you got interrupted and want to resume, or when you want the AI to keep iterating without stopping early.
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
```
|
|
27
|
+
/auto-loop --ralph Continue the refactoring
|
|
28
|
+
/auto-loop --ralph --max 10 Fix all lint errors
|
|
29
|
+
```
|
|
30
|
+
|
|
22
31
|
### `/cancel-auto-loop`
|
|
23
32
|
Cancel an active Auto Loop before it completes.
|
|
24
33
|
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ interface LoopState {
|
|
|
16
16
|
iteration: number;
|
|
17
17
|
maxIterations: number;
|
|
18
18
|
debounceMs: number;
|
|
19
|
+
forceLoop?: boolean;
|
|
19
20
|
sessionId?: string;
|
|
20
21
|
prompt?: string;
|
|
21
22
|
completed?: string;
|
|
@@ -124,6 +125,7 @@ function parseState(content: string): LoopState {
|
|
|
124
125
|
if (key === "iteration") state.iteration = parseInt(value) || 0;
|
|
125
126
|
if (key === "maxIterations") state.maxIterations = parseInt(value) || DEFAULT_MAX_ITERATIONS;
|
|
126
127
|
if (key === "debounceMs") state.debounceMs = parseInt(value) || DEFAULT_DEBOUNCE_MS;
|
|
128
|
+
if (key === "forceLoop") state.forceLoop = value === "true";
|
|
127
129
|
if (key === "sessionId") state.sessionId = value || undefined;
|
|
128
130
|
}
|
|
129
131
|
|
|
@@ -159,6 +161,7 @@ function serializeState(state: LoopState): string {
|
|
|
159
161
|
`maxIterations: ${state.maxIterations}`,
|
|
160
162
|
`debounceMs: ${state.debounceMs}`,
|
|
161
163
|
];
|
|
164
|
+
if (state.forceLoop) lines.push(`forceLoop: ${state.forceLoop}`);
|
|
162
165
|
if (state.sessionId) lines.push(`sessionId: ${state.sessionId}`);
|
|
163
166
|
lines.push("---");
|
|
164
167
|
if (state.prompt) lines.push("", state.prompt);
|
|
@@ -412,16 +415,24 @@ function buildProgressSection(state: LoopState): string {
|
|
|
412
415
|
// Build the loop context reminder for post-compaction injection
|
|
413
416
|
function buildLoopContextReminder(state: LoopState): string {
|
|
414
417
|
const progress = buildProgressSection(state);
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
418
|
+
const forceLabel = state.forceLoop ? " [FORCE MODE]" : "";
|
|
419
|
+
const rules = state.forceLoop
|
|
420
|
+
? `IMPORTANT RULES:
|
|
421
|
+
- Before going idle, output ## Completed and ## Next Steps sections
|
|
422
|
+
- FORCE MODE is active — the loop will continue for all ${state.maxIterations} iterations regardless of completion signals
|
|
423
|
+
- Focus on making steady progress each iteration`
|
|
424
|
+
: `IMPORTANT RULES:
|
|
420
425
|
- Before going idle, output ## Completed and ## Next Steps sections
|
|
421
426
|
- You MUST include a STATUS line: either \`STATUS: IN_PROGRESS\` or \`STATUS: COMPLETE\` on its own line
|
|
422
427
|
- Do NOT output <promise>DONE</promise> if there are ANY unchecked items (\`- [ ]\`) in your Next Steps — the plugin WILL reject it
|
|
423
428
|
- Only output \`STATUS: COMPLETE\` and the DONE signal when ALL steps are truly finished and Next Steps is empty
|
|
424
429
|
- Do NOT output false completion promises. If blocked, output \`STATUS: IN_PROGRESS\` and explain the blocker.`;
|
|
430
|
+
|
|
431
|
+
return `[AUTO LOOP${forceLabel} ACTIVE — Iteration ${state.iteration}/${state.maxIterations}]
|
|
432
|
+
|
|
433
|
+
Original task: ${state.prompt || "(no task specified)"}
|
|
434
|
+
${progress}
|
|
435
|
+
${rules}`;
|
|
425
436
|
}
|
|
426
437
|
|
|
427
438
|
// Check if session is currently busy (not idle)
|
|
@@ -504,8 +515,12 @@ export const AutoLoopPlugin: Plugin = async (ctx) => {
|
|
|
504
515
|
.number()
|
|
505
516
|
.optional()
|
|
506
517
|
.describe("Debounce delay between iterations in ms (default: 2000)"),
|
|
518
|
+
forceLoop: tool.schema
|
|
519
|
+
.boolean()
|
|
520
|
+
.optional()
|
|
521
|
+
.describe("Force mode (--ralph): ignore completion signals and run for all iterations"),
|
|
507
522
|
},
|
|
508
|
-
async execute({ task, maxIterations = DEFAULT_MAX_ITERATIONS, debounceMs = DEFAULT_DEBOUNCE_MS }, context) {
|
|
523
|
+
async execute({ task, maxIterations = DEFAULT_MAX_ITERATIONS, debounceMs = DEFAULT_DEBOUNCE_MS, forceLoop = false }, context) {
|
|
509
524
|
if (context.abort.aborted) return "Auto Loop start was cancelled.";
|
|
510
525
|
|
|
511
526
|
const state: LoopState = {
|
|
@@ -513,6 +528,7 @@ export const AutoLoopPlugin: Plugin = async (ctx) => {
|
|
|
513
528
|
iteration: 0,
|
|
514
529
|
maxIterations,
|
|
515
530
|
debounceMs,
|
|
531
|
+
forceLoop: forceLoop ? true : undefined,
|
|
516
532
|
sessionId: context.sessionID,
|
|
517
533
|
prompt: task,
|
|
518
534
|
};
|
|
@@ -521,16 +537,21 @@ export const AutoLoopPlugin: Plugin = async (ctx) => {
|
|
|
521
537
|
continuationInFlight = false;
|
|
522
538
|
lastContinuation = 0;
|
|
523
539
|
|
|
524
|
-
|
|
525
|
-
|
|
540
|
+
const modeLabel = forceLoop ? " [FORCE MODE]" : "";
|
|
541
|
+
log("info", `Loop started${modeLabel} for session ${context.sessionID}`);
|
|
542
|
+
toast(`Auto Loop started${modeLabel} (max ${maxIterations} iterations)`, "success");
|
|
526
543
|
|
|
527
|
-
|
|
544
|
+
const forceNote = forceLoop
|
|
545
|
+
? `\n\n**FORCE MODE (--ralph):** Completion signals are IGNORED. The loop will run for all ${maxIterations} iterations regardless. Focus on making progress each iteration — you do NOT need to output STATUS or DONE signals.`
|
|
546
|
+
: "";
|
|
547
|
+
|
|
548
|
+
return `Auto Loop started (max ${maxIterations} iterations).${forceNote}
|
|
528
549
|
|
|
529
550
|
Task: ${task}
|
|
530
551
|
|
|
531
|
-
**Begin working on the task now.** The loop will auto-continue until you signal completion.
|
|
552
|
+
**Begin working on the task now.** The loop will auto-continue until ${forceLoop ? `all ${maxIterations} iterations are used` : "you signal completion"}.
|
|
532
553
|
|
|
533
|
-
Before going idle each iteration, output structured progress AND a status line:
|
|
554
|
+
Before going idle each iteration, output structured progress${forceLoop ? "" : " AND a status line"}:
|
|
534
555
|
|
|
535
556
|
\`\`\`
|
|
536
557
|
## Completed
|
|
@@ -538,10 +559,9 @@ Before going idle each iteration, output structured progress AND a status line:
|
|
|
538
559
|
|
|
539
560
|
## Next Steps
|
|
540
561
|
- [ ] What remains (in priority order)
|
|
541
|
-
|
|
542
|
-
STATUS: IN_PROGRESS
|
|
562
|
+
${forceLoop ? "" : "\nSTATUS: IN_PROGRESS"}
|
|
543
563
|
\`\`\`
|
|
544
|
-
|
|
564
|
+
${forceLoop ? "" : `
|
|
545
565
|
## Completion Rules — READ CAREFULLY
|
|
546
566
|
|
|
547
567
|
1. **If your Next Steps list has ANY unchecked items (\`- [ ]\`), you MUST NOT output the DONE signal.** The plugin will reject it.
|
|
@@ -550,7 +570,7 @@ STATUS: IN_PROGRESS
|
|
|
550
570
|
- \`STATUS: COMPLETE\` on its own line
|
|
551
571
|
- The promise-DONE XML tag on its own line
|
|
552
572
|
4. If you are blocked or stuck, output \`STATUS: IN_PROGRESS\` and explain the blocker. Do NOT output a false DONE.
|
|
553
|
-
|
|
573
|
+
`}
|
|
554
574
|
Use /cancel-auto-loop to stop early.`;
|
|
555
575
|
},
|
|
556
576
|
}),
|
|
@@ -585,6 +605,8 @@ Use /cancel-auto-loop to stop early.`;
|
|
|
585
605
|
|
|
586
606
|
- \`/auto-loop <task>\` - Start an auto-continuation loop (default: 25 iterations)
|
|
587
607
|
- \`/auto-loop <task> --max <n>\` - Start with a custom iteration limit
|
|
608
|
+
- \`/auto-loop <task> --ralph\` - Force mode: ignore completion signals, run all iterations
|
|
609
|
+
- \`/auto-loop <task> --ralph --max <n>\` - Force mode with custom limit
|
|
588
610
|
- \`/cancel-auto-loop\` - Stop an active loop
|
|
589
611
|
- \`/auto-loop-help\` - Show this help
|
|
590
612
|
|
|
@@ -592,6 +614,8 @@ Use /cancel-auto-loop to stop early.`;
|
|
|
592
614
|
|
|
593
615
|
- \`/auto-loop Build a REST API\` — runs up to 25 iterations
|
|
594
616
|
- \`/auto-loop Fix all lint errors --max 10\` — runs up to 10 iterations
|
|
617
|
+
- \`/auto-loop --ralph Continue refactoring\` — force runs all 25 iterations, ignores DONE signals
|
|
618
|
+
- \`/auto-loop --ralph --max 50 Big migration\` — force runs all 50 iterations
|
|
595
619
|
|
|
596
620
|
## How It Works
|
|
597
621
|
|
|
@@ -600,6 +624,13 @@ Use /cancel-auto-loop to stop early.`;
|
|
|
600
624
|
3. Plugin auto-continues if not complete
|
|
601
625
|
4. Loop stops when AI outputs: <promise>DONE</promise>
|
|
602
626
|
|
|
627
|
+
## Force Mode (--ralph)
|
|
628
|
+
|
|
629
|
+
When \`--ralph\` is used, the loop ignores ALL completion signals and runs for the full iteration count. Useful when:
|
|
630
|
+
- You got interrupted and want to continue no matter what
|
|
631
|
+
- You want the AI to keep iterating and improving
|
|
632
|
+
- You don't want the AI to stop early
|
|
633
|
+
|
|
603
634
|
## State File
|
|
604
635
|
|
|
605
636
|
Located at: .opencode/auto-loop.local.md`;
|
|
@@ -632,8 +663,10 @@ Located at: .opencode/auto-loop.local.md`;
|
|
|
632
663
|
const lastText = await getLastAssistantText(client, sessionId, directory, log);
|
|
633
664
|
|
|
634
665
|
// Skip completion check on iteration 0 (first idle after loop start)
|
|
635
|
-
// to avoid false positives from the tool's initial response text
|
|
636
|
-
|
|
666
|
+
// to avoid false positives from the tool's initial response text.
|
|
667
|
+
// Also skip entirely when forceLoop is true — force mode ignores
|
|
668
|
+
// all completion signals and runs until max iterations.
|
|
669
|
+
if (!state.forceLoop && state.iteration > 0 && lastText && checkCompletion(lastText)) {
|
|
637
670
|
// Validate the DONE signal — reject if there are unchecked steps
|
|
638
671
|
// or if the STATUS signal contradicts completion
|
|
639
672
|
const validation = validateCompletion(lastText);
|
|
@@ -673,17 +706,26 @@ Located at: .opencode/auto-loop.local.md`;
|
|
|
673
706
|
// Build continuation prompt with progress context
|
|
674
707
|
const progressSection = buildProgressSection(newState);
|
|
675
708
|
|
|
676
|
-
const
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
709
|
+
const forceLabel = state.forceLoop ? " [FORCE MODE]" : "";
|
|
710
|
+
const importantRules = state.forceLoop
|
|
711
|
+
? `IMPORTANT:
|
|
712
|
+
- Pick up from the next incomplete step below
|
|
713
|
+
- Before going idle, list your progress using ## Completed and ## Next Steps sections
|
|
714
|
+
- FORCE MODE is active — the loop will continue for all ${newState.maxIterations} iterations regardless of completion signals
|
|
715
|
+
- Focus on making steady progress each iteration`
|
|
716
|
+
: `IMPORTANT:
|
|
681
717
|
- Pick up from the next incomplete step below
|
|
682
718
|
- Before going idle, list your progress using ## Completed and ## Next Steps sections
|
|
683
719
|
- You MUST include a STATUS line: either \`STATUS: IN_PROGRESS\` or \`STATUS: COMPLETE\` on its own line
|
|
684
720
|
- Do NOT output <promise>DONE</promise> if there are ANY unchecked items (\`- [ ]\`) in your Next Steps — the plugin WILL reject it
|
|
685
721
|
- Only output \`STATUS: COMPLETE\` and the DONE signal when ALL steps are truly finished and Next Steps is empty
|
|
686
|
-
- Do not stop until the task is truly done
|
|
722
|
+
- Do not stop until the task is truly done`;
|
|
723
|
+
|
|
724
|
+
const continuationPrompt = `[AUTO LOOP${forceLabel} — ITERATION ${newState.iteration}/${newState.maxIterations}]
|
|
725
|
+
|
|
726
|
+
Continue working on the task. Do NOT repeat work that is already done.
|
|
727
|
+
${progressSection}
|
|
728
|
+
${importantRules}
|
|
687
729
|
|
|
688
730
|
Original task:
|
|
689
731
|
${state.prompt || "(no task specified)"}`;
|