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.
@@ -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 an optional `--max <number>` flag.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-auto-loop",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Auto-continue for OpenCode",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -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
- return `[AUTO LOOP ACTIVE Iteration ${state.iteration}/${state.maxIterations}]
416
-
417
- Original task: ${state.prompt || "(no task specified)"}
418
- ${progress}
419
- IMPORTANT RULES:
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
- log("info", `Loop started for session ${context.sessionID}`);
525
- toast(`Auto Loop started (max ${maxIterations} iterations)`, "success");
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
- return `Auto Loop started (max ${maxIterations} iterations).
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
- if (state.iteration > 0 && lastText && checkCompletion(lastText)) {
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 continuationPrompt = `[AUTO LOOP ITERATION ${newState.iteration}/${newState.maxIterations}]
677
-
678
- Continue working on the task. Do NOT repeat work that is already done.
679
- ${progressSection}
680
- IMPORTANT:
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)"}`;